package server

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"strconv"
	"time"
)

type Restful struct {
	URL         *url.URL
	ContentType string
}

type RestfulOption struct {
	URL         string
	ContentType string
	Runner      func(platform *Platform) error
}

func NewRestful(option RestfulOption) (*Restful, error) {
	u, err := url.Parse(option.URL)
	if err != nil {
		return nil, err
	}
	return &Restful{
		URL:         u,
		ContentType: option.ContentType,
	}, nil
}

func (d *Restful) Callback(task *Task) {
	log.Printf("restful job running")
	err := d.do(task)
	if err != nil {
		go d.retry(task, 5)
	}
}

func (d *Restful) Start(platform *Platform) error {
	return nil
}

func (d *Restful) Stop() {

}

func (d *Restful) do(task *Task) error {
	log.Printf("post to %s", d.URL.String())
	fmt.Println(task)
	http.DefaultClient.Timeout = 10 * time.Second
	_, err := http.Post(d.URL.String(), d.ContentType, task)
	if err != nil {
		log.Printf("post to %s error: %s", d.URL.String(), err)
		return err
	}
	log.Printf("post to %s success", d.URL.String())
	return nil
}

// retry 失败任务重试
func (d *Restful) retry(task *Task, times int) {
	for i := 0; i < times; i++ {
		log.Printf("retry task %s: %d", task.Name, i+1)
		err := d.do(task)
		if err == nil {
			return
		}
		time.Sleep(time.Second)
	}
	log.Printf("task %s failed", task.Name)
}

func RunRestfulServer(s *Scheduler) error {
	log.Printf("run restful sever")
	http.HandleFunc("/tasks", func(writer http.ResponseWriter, request *http.Request) {
		if request.Method != "POST" {
			writer.WriteHeader(405)
			writer.Write([]byte("Method Not Allowed"))
			return
		}
		platform, err := s.GetPlatform(request.Header.Get("X-PLATFORM"))
		if err != nil {
			writer.WriteHeader(400)
			writer.Write([]byte(err.Error()))
			return
		}
		task, err := newTaskFromRequest(request)
		if err != nil {
			writer.WriteHeader(400)
			writer.Write([]byte(err.Error()))
			return
		}

		err = platform.AddTask(task)
		if err != nil {
			writer.WriteHeader(500)
			writer.Write([]byte(err.Error()))
			return
		}
		writer.Write([]byte("success"))
	})
	srv := http.Server{
		Addr: ":8887",
	}
	return srv.ListenAndServe()
}

func newTaskFromRequest(r *http.Request) (*Task, error) {
	delay, err := strconv.Atoi(r.Header.Get("X-TASK-DELAY"))
	if err != nil {
		return nil, err
	}
	payload, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return nil, err
	}
	return &Task{
		Name:    r.Header.Get("X-TASK-NAME"),
		Payload: payload,
		Delay:   time.Duration(delay) * time.Second,
	}, nil
}

func RestfulOptionSetter(option RestfulOption) OptionCall {
	return func(platform *Platform) {
		platform.SetOption(RESTFUL, option)
	}
}
